package top.lixunda.ecommerce.server.business.api.entity.dto;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import top.lixunda.commerce.common.core.exception.AppException;
import top.lixunda.common.utils.ObjectValidators;

import java.util.List;
import java.util.Map;

/**
 * @author Xumda
 * @version time:2020/2/24 17:51
 * <p>
 * 保存有排序规则的DTO
 */
@SuppressWarnings("WeakerAccess")
@Slf4j
@ApiModel(value = "排序参数DTO", description = "通用排序参数DTO，当进行复杂查询时排序使用")
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class OrderByDTO {

    /**
     * 排序数据
     */
    @ApiModelProperty(value = "排序规则", notes = "多个排序规则，有顺序")
    private List<OrderByEntity> orderByList;

    /**
     * 处理排序字段
     *
     * @param wrapper       Wrapper
     * @param orderByEntity OrderByEntity
     * @param column        排序字段
     */
    private <D> void dealWithOrderBy(final LambdaQueryWrapper<D> wrapper,
                                final OrderByEntity orderByEntity,
                                final SFunction<D, ?> column) {
        if (OrderByEntity.SORT_ASC.equals(orderByEntity.getOrder().toUpperCase())) {
            wrapper.orderByAsc(column);
        } else {
            wrapper.orderByDesc(column);
        }
    }

    /**
     * 处理排序字段
     *
     * @param wrapper       Wrapper
     * @param orderByEntity OrderByEntity
     * @param columns       字段集合
     */
    private <D> void dealWithOrderByEntity(final LambdaQueryWrapper<D> wrapper,
                                      final OrderByEntity orderByEntity,
                                      final Map<String, SFunction<D, ?>> columns) {
        SFunction<D, ?> column = columns.get(orderByEntity.getColumn());
        if (ObjectValidators.isEmpty(column)) {
            log.debug("不存在的字段");
            return;
        }
        dealWithOrderBy(wrapper, orderByEntity, column);
    }

    /**
     * 处理排序字段
     *
     * @param wrapper Wrapper
     * @param columns 字段集合
     */
    public <D> void dealWithOrderBy(final LambdaQueryWrapper<D> wrapper,
                                final Map<String, SFunction<D, ?>> columns) {
        if (ObjectValidators.isEmpty(wrapper)) {
            log.debug("Wrapper不能为空");
            throw new AppException("Wrapper不能为空");
        }
        if (ObjectValidators.isEmpty(columns)) {
            log.debug("参数错误 dealWithOrderByEntity columns");
            return;
        }
        if (ObjectValidators.isEmpty(this.getOrderByList())) {
            return;
        }
        this.getOrderByList().forEach(item ->
                dealWithOrderByEntity(wrapper, item, columns));
    }

    @SuppressWarnings("unused")
    @ApiModel(value = "排序DTO", description = "单个排序字段的DTO")
    @Data
    @EqualsAndHashCode(callSuper = false)
    @Accessors(chain = true)
    public static class OrderByEntity {

        /**
         * 排序方式，顺序
         */
        @ApiModelProperty(hidden = true)
        @JsonIgnore
        public static final String SORT_ASC = "ASC";

        /**
         * 排序方式，倒序
         */
        @ApiModelProperty(hidden = true)
        @JsonIgnore
        public static final String SORT_DESC = "DESC";

        /**
         * 排序字段
         */
        @ApiModelProperty(value = "排序字段", notes = "排序的字段，一般对应数据表实体类中的属性名")
        private String column;

        /**
         * 排序方式
         */
        @ApiModelProperty(value = "排序方式", notes = "ASC 升序排列  DESC 降序排列")
        private String order;

        /**
         * 设置为ASC
         *
         * @return this
         */
        public OrderByEntity setAsc() {
            this.setOrder(OrderByEntity.SORT_ASC);
            return this;
        }

        /**
         * 设置为DESC
         *
         * @return this
         */
        public OrderByEntity setDesc() {
            this.setOrder(OrderByEntity.SORT_DESC);
            return this;
        }
    }

}
